package com.example.yuntiku.dao;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class BaseDao {
    //声明日志记录对象
    static Logger log = LogManager.getLogger(BaseDao.class.getName());
    //数据库连接的4个重要信息
    private static String driver;  //驱动类
    private static String url; //连接字符串
    private static String username; //用户名
    private static String password; //密码

    //连接对象
    public Connection conn = null;

    //静态块读取database.properties文件中的连接信息
    static {
        Properties properties = new Properties();
        InputStream is = BaseDao.class.getClassLoader()
                .getResourceAsStream("database.properties");
        try {
            properties.load(is);
            //读取4个重要信息
            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获得连接对象的
     *
     * @return
     */
    public Connection getConnection() {
        try {
            //判断conn连接对象是否为空或已关闭
            if (conn == null || conn.isClosed()) {
                Class.forName(driver);
                conn = DriverManager.getConnection(url, username, password);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return conn;
    }

    /**
     * 关闭数据库操作对象
     *
     * @param conn
     * @param stmt
     * @param rs
     */
    public void closeAll(Connection conn, Statement stmt, ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 执行增删改的封装的方法
     *
     * @param sql   增删改的sql语句
     * @param param 参数
     * @return 返回受影响的行数
     */
    public int executeUpdate(String sql, Object... param) {
        PreparedStatement stmt = null;
        conn = getConnection(); //调用上面的方法，获得连接对象

        try {
            //使用日志记录sql语句
            log.debug(sql);
            stmt = conn.prepareStatement(sql);
            //有参数则设置参数
            if (param != null && param.length > 0) {
                for (int i = 0; i < param.length; i++) {
                    //setObject：不管什么类型都可以设置
                    stmt.setObject(i + 1, param[i]);
                    //使用日志输出参数
                    log.debug("参数"+(i+1)+":"+param[i]);
                }
            }
            //执行增删改
            return stmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            closeAll(conn, stmt, null);
        }
    }

    /**
     * 统计总数的通用方法
     * @param sql
     * @param param
     * @return
     */
    public int count(String sql, Object... param){
        //定义数据库操作对象
        PreparedStatement stmt = null;
        ResultSet rs = null;//读取结果集

        try {
            conn = getConnection();
            stmt = conn.prepareStatement(sql);
            //使用日志记录sql语句
            log.debug(sql);
            //有参数则设置参数
            if (param != null && param.length > 0) {
                for (int i = 0; i < param.length; i++) {
                    //setObject：不管什么类型都可以设置
                    stmt.setObject(i + 1, param[i]);
                    //使用日志输出参数
                    log.debug("参数"+(i+1)+":"+param[i]);
                }
            }
            rs = stmt.executeQuery();
            //循环读取查询的记录
            while (rs.next()) { //一次读取一行记录，读完返回false
                return rs.getInt(1);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            this.closeAll(conn, stmt, rs);
        }
        return 0;
    }

    /**
     * 封装查询方法
     * @param sql
     * @param param
     * @return
     */
    public ResultSet executeQuery(String sql, Object... param) {
        PreparedStatement stmt = null;
        conn = getConnection(); //调用上面的方法，获得连接对象

        try {
            //使用日志记录sql语句
            log.debug(sql);
            stmt = conn.prepareStatement(sql);

            //有参数则设置参数
            if (param != null && param.length > 0) {
                for (int i = 0; i < param.length; i++) {
                    //setObject：不管什么类型都可以设置
                    stmt.setObject(i + 1, param[i]);
                    //使用日志输出参数
                    log.debug("参数"+(i+1)+":"+param[i]);
                }
            }
            //执行增删改
            return stmt.executeQuery();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 执行添加后返回自增的值
     * @param sql
     * @param param
     * @return
     */
    public int insertForId(String sql,Object...param){
        PreparedStatement stmt = null;
        conn = getConnection(); //调用上面的方法，获得连接对象
        ResultSet rs = null;
        try {
            //使用日志记录sql语句
            log.debug(sql);
            stmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
            //有参数则设置参数
            if (param != null && param.length > 0) {
                for (int i = 0; i < param.length; i++) {
                    //setObject：不管什么类型都可以设置
                    stmt.setObject(i + 1, param[i]);
                    //使用日志输出参数
                    log.debug("参数"+(i+1)+":"+param[i]);
                }
            }
            //执行增删改
            stmt.executeUpdate();
            rs = stmt.getGeneratedKeys();
            if(rs.next()){
                return rs.getInt(1);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            closeAll(conn, stmt, null);
        }
        return 0;
    }
}
